#include "Game.hh"
#include <iostream>
#include <memory>
#include <windows.h>

namespace Game {

    bool playOneRun(MetaProgress& progress) {
        Map map;
        Player player = progress.createPlayer();
        int apResetUsed = 0;
        const int maxApReset = 3;
    
        IO::showIntroduction();
    
        while (player.isAlive()) {
            auto* currentRoom = map.getCurrentRoom();//Get the type of the pointer automatically
    
            // 使用 dynamic_cast 尝试将 currentRoom 指针转换为 RestRoom 类型的指针。
            // 如果 currentRoom 实际上指向一个 RestRoom 对象（或其子类），
            // 则转换成功，restRoom 将指向这个对象；否则返回 nullptr。
            // Attempt to downcast the currentRoom pointer to a RestRoom* using dynamic_cast.
            // If currentRoom actually points to a RestRoom object (or derived from it),
            // the cast will succeed and restRoom will point to it; otherwise, it returns nullptr.
            if (auto* restRoom = dynamic_cast<RestRoom*>(currentRoom)) {
                if (restRoom->hasEscapeUnlocked()) {
                    IO::showEscapeEnd();
                    progress.gainProgress(false, false);
                    progress.displayProgress();
                    return true; // 游戏结束，继续新 run
                }
            }
    
            if (auto* bossRoom = dynamic_cast<BossRoom*>(currentRoom)) {
                if (bossRoom->hasWon()) {
                    std::cout << "\n[Boss Defeated - Battle Ending Achieved!]\n";
                    progress.gainProgress(true, false);
                    progress.displayProgress();
                    return true;
                }
            }
    
            std::cout << "\n=== Floor " << map.getCurrentLayer()
                      << " | AP: " << player.getAP()
                      << " | Rooms Visited: " << map.getRoomsVisitedThisLayer() << " ===\n";
    
            IO::showMainMenu();
            int choice = IO::getNumber();
            switch (choice) {
                case 1: {
                    if (player.getAP() <= 0) {
                        std::cout << "[No AP left! Consider ending your turn.]\n";
                        break;
                    }
                    clearScreen();
                    Sleep(100);
                    map.moveInDirection(player, true);
                    break;
                }
                case 2:
                    player.displayStatus();
                    break;
                case 3:
                    clearScreen();
                    if (apResetUsed < maxApReset) {
                        apResetUsed++;
                        player.setAP(progress.getMaxAp());
                        player.decreaseMaxHP(10);
                        IO::endTurn(apResetUsed,maxApReset);
                        std::cout << "[Current Max HP: " << player.getMaxHealth() << "]\n";
                    } else if (apResetUsed >= maxApReset && player.getAP() == 0) {
                        std::cout << "[No AP resets remaining.]\n";
                        std::cout << "\n[You have fallen. Ending: LOST]\n";
                        progress.gainProgress(false, false);
                        progress.displayProgress();
                        return true;
                    } else {
                        std::cout << "[No AP resets remaining.]\n";
                        std::cout << "Use your AP carefully!\n";
                    }
                    break;
                case 4:
                    std::cout << "Thanks for playing!\n";
                    return false; // 玩家主动退出
                default:
                    std::cout << "Invalid choice.\n";
            }
        }
        std::cout << "\n[You have fallen. Ending: DEAD]\n";
        progress.gainProgress(false, true);
        progress.displayProgress();
        return true;
    }
    

    void run() {
        clearScreen();
        MetaProgress progress;

        while (true) {
            bool continueGame = playOneRun(progress);

            if (!continueGame) {
                break;
            }
            std::cout << "\nStart a new run? (y/n): ";
            std::string input=IO::getString();
            while (input!="n"&&input!="N" &&input!="Y"&&input!="y")
            {
                cout<<"Invalid input. Try again: ";
                input=IO::getString();
            }
            if (input == "n" || input == "N") {
                std::cout << "Goodbye!\n";
                break;
            } else if(input=="Y" ||input=="y"){
                clearScreen();
            }
        }
    }
}
